package com.gary.shiro.config.shiro;

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {
  
  //必须实现 
  @Bean
  public ShiroFilterFactoryBean filterFactoryBean(DefaultWebSecurityManager shiroManager,
                                                  ShiroFilterChainDefinition shiroFilterChainDefinition,
                                                  FilterRegistrationBean filterRegistrationBean){
    ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
    filterFactoryBean.setSecurityManager(shiroManager);
    Map<String, Filter> filterMap=new LinkedHashMap<>(8);
    filterMap.put("authc",filterRegistrationBean.getFilter());
    filterFactoryBean.setFilters(filterMap);
    filterFactoryBean.setFilterChainDefinitionMap(shiroFilterChainDefinition.getFilterChainMap());
    return filterFactoryBean;
  }

  /**
   * 在此处配置过滤器链
   */
  @Bean
  public ShiroFilterChainDefinition shiroFilterChainDefinition() {
    DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
    //这些请求不通过shiroFilter
//    chainDefinition.addPathDefinition("/hello","anon");
//    chainDefinition.addPathDefinition("/api/gary/shiro/admin/login","anon");
    // 所有请求通过我们自己的shiro Filter
    chainDefinition.addPathDefinition("/**","anon");
    return chainDefinition;
  }

  /**
   * 配置shiroFilter过滤器,并设置为未注册状态
   */
  @Bean
  public FilterRegistrationBean filterRegistrationBean() {
    FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
    //添加shiroFilter  并设置为未注册状态
    filterRegistrationBean.setFilter(new ShiroFilter());
    filterRegistrationBean.setEnabled(false);
    return filterRegistrationBean;
  }

  @Bean
  public DefaultWebSecurityManager shiroManager(ShiroRealm shiroRealm, DefaultWebSessionManager sessionManager){
    DefaultWebSecurityManager shiroManager = new DefaultWebSecurityManager();
    shiroManager.setSessionManager(sessionManager);
    shiroManager.setRealm(shiroRealm);
    return shiroManager;
  }

  @Bean
  public ShiroRealm shiroRealm(HashedCredentialsMatcher hashedCredentialsMatcher){
    ShiroRealm shiroRealm = new ShiroRealm();
    shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher); //设置加密matcher
    return shiroRealm;
  }

  //如果需要通过shiro对密码进行加密 则需要配置HashedCredentailsMatcher
  @Bean
  public HashedCredentialsMatcher hashedCredentialsMatcher(){
    HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
    hashedCredentialsMatcher.setHashAlgorithmName("md5"); //设置算法名称
    hashedCredentialsMatcher.setHashIterations(8); //hash的迭代次数 就是进行多少次hash加密
    return hashedCredentialsMatcher;
  }

  @Bean
  public DefaultWebSessionManager sessionManager(ShiroSessionDAO shiroSessionDAO ){
    DefaultWebSessionManager sessionManager  = new DefaultWebSessionManager();
    sessionManager.setSessionDAO(shiroSessionDAO); //设置为自己的session管理
    return sessionManager;
  }

  //开启shiro的注解支持
  @Bean
  public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager shiroManager){
    AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
    authorizationAttributeSourceAdvisor.setSecurityManager(shiroManager);
    return authorizationAttributeSourceAdvisor;
  }
 
  //开启shiro注解支持
  @Bean
  public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
    DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
    defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
    defaultAdvisorAutoProxyCreator.setUsePrefix(true);
    return defaultAdvisorAutoProxyCreator;
  }

  //redis的序列化方式全部采用默认的方式 用json序列化会出问题
  @Bean
  public RedisTemplate<String, Object> shiroRedisTemplate(RedisConnectionFactory lettuceConnectionFactory) {
    RedisTemplate<String, Object> template = new RedisTemplate<>();
    template.setConnectionFactory(lettuceConnectionFactory);
    template.setKeySerializer(new StringRedisSerializer());
    //template 新建后必须调用得初始化操作 当无自定义设置得序列器 方法中会使用默认
    template.afterPropertiesSet();
    return template;
  }
}